432D - Prefixes and Suffixes - CodeForces Solution


dp string suffix structures strings two pointers *2000

Please click on ads to support us..

Python Code:

import io
import os
import sys


def calc_lps(pat):
    lps = [-1] * len(pat)
    cand = -1
    for i in range(1, len(pat)):
        while cand >= 0 and pat[i] != pat[cand + 1]:
            cand = lps[cand]
        if pat[i] == pat[cand + 1]:
            cand += 1
        lps[i] = cand
    return lps



s = input()
n = len(s)
lps = calc_lps(s)
cnt = [1] * (n + 1)
for i in range(n - 1, 0, -1):
    if lps[i] >= 0:
        cnt[lps[i] + 1] += cnt[i + 1]
ans = []
cur = n - 1
while cur != -1:
    ans.append((cur + 1, cnt[cur + 1]))
    cur = lps[cur]
print(len(ans))
for l, c in ans[::-1]:
    print(l, c)




C++ Code:

#include <bits/stdc++.h>

using namespace std;
const int N_MAX = 1e5;


/// Observatii si comentarii :
/// In primul rand trebuie sa aflam prefixele care respecta conditia din enunt
/// Cel mai lung dintre ele este chiar raspunsul dat de KMP --> LPS[n - 1]
/// Fie Pk lungimea prefixului curent. Atunci urmatorul cel mai lung prefix va fi cel de lungime LPS[Pk - 1]
/// Nota : Sirul de lungime n se adauga la inceput cu frecventa 1
/// In al doilea rand trebuie sa aflam frecventele acestor prefixe
/// Ne propunem sa aflam pentru o pozitie i sa aflam ce prefixe se termina pe acea pozitie
/// In aceeasi maniera, cel mai lung dintre ele este LPS[i]
/// Fie Pk prefixului curent. Atunci urmatorul cel mai lung prefix va fi cel de lungime LPS[Pk - 1]
/// Astfel pentru fiecare pozitie i = 0..n - 1 se formeaza un sir de prefixe care apar
/// Aceste siruri sunt descrescatoare si urmeaza regula prefix --> LPS[prefix - 1]
/// Momentan noi cunoastem doar frecventa "sefilor" de sir (primului numar din sir)
/// Pentru a frecventa lui LPS[prefix - 1] trebuie mai intai sa aflam frecventa lui prefix
/// Asadar ar fi minunat daca am gasi o sortare topologica a acestor prefixe
/// => graful format de aceste prefix trebuie sa fie unul directionat si aciclic
/// cunoastem ca este directionat si este chiar si aciclic deoarece sirurile sunt descrescatoare
/// Altfel spus, nu ne putem intoarce de la ceva mic la ceva mare
/// Asadar formam graful, il sortam topologic iar frecv[LPS[prefix - 1]] += frecv[prefix]
/// deoarece unde apare prefix sigur apare si LPS[prefix - 1]

int LPS[1 + N_MAX];
int frecv[1 + N_MAX];

vector<int> DAG[1 + N_MAX];
void KMP (string input) {
   int n = input.size (); LPS[0] = 0;

   int k = 0; /// curr lps
   for (int i = 1; i < n; i ++) {
      while (k > 0 && input[i] != input[k])
         k = LPS[k - 1];
      if (input[i] == input[k])
        k ++;

      LPS[i] = k;

      frecv[k] ++;
      if (frecv[k] == 1) /// adaosul prefix -- LPS[prefix - 1] trebuie sa se intample exact o data
        DAG[k].push_back (LPS[k - 1]);
   }
}


vector<int> topoSort;
bool visited[1 + N_MAX];

void dfs (int root) {
   visited[root] = true;
   for (int node : DAG[root])
      if (!visited[node])
        dfs (node);
   topoSort.push_back (root);
}

struct defAnswer {
   int preff, counter;
};

int main()
{
   string input; cin >> input;
   KMP (input);

   int n = input.size ();
   for (int preff = 0; preff < n; preff ++)
      if (!visited[preff])
        dfs (preff);

   reverse (topoSort.begin (), topoSort.end ());

   for (int node : topoSort) {
      for (int u : DAG[node])
         frecv[u] += frecv[node];
   }
   vector<defAnswer> answer;
   answer.push_back ({n, 1});

   int k = LPS[n - 1];
   while (k > 0) {
      answer.push_back ({k, 1 + frecv[k]}); /// adunam 1 pentru a considera si prefixul in sine care NU este considerat de KMP
      k = LPS[k - 1];
   }
   reverse (answer.begin (), answer.end ());

   cout << answer.size () << "\n";
   for (defAnswer obj : answer) {
      cout << obj.preff << " " << obj.counter;
      cout << "\n";
   }
    return 0;
}


Comments

Submit
0 Comments
More Questions

519A - A and B and Chess
725B - Food on the Plane
154B - Colliders
127B - Canvas Frames
107B - Basketball Team
245A - System Administrator
698A - Vacations
1216B - Shooting
368B - Sereja and Suffixes
1665C - Tree Infection
1665D - GCD Guess
29A - Spit Problem
1097B - Petr and a Combination Lock
92A - Chips
1665B - Array Cloning Technique
1665A - GCD vs LCM
118D - Caesar's Legions
1598A - Computer Game
1605A - AM Deviation
1461A - String Generation
1585B - Array Eversion
1661C - Water the Trees
1459A - Red-Blue Shuffle
1661B - Getting Zero
1661A - Array Balancing
1649B - Game of Ball Passing
572A - Arrays
1455A - Strange Functions
1566B - MIN-MEX Cut
678C - Joty and Chocolate